#include <stdlib.h>
#include <assert.h>
#include <err.h>

#include "glib/glist.h"
#include "node.h"
#include "edge.h"

struct sNode {
    unsigned int label; /* Número que identifica al nodo */
    bool marked; /* Está marcado el nodo? */
    node father; /* Padre del nodo */
    GList *neighbors; /* Lista de vecinos del nodo */
};

/* Obtiene el edge dado un nodo y el label de su vecino */
edge node_getEdge(const node n, const unsigned int label);

node node_create(const unsigned int label){
    /* Asigno memoria para alojar la estructura */
    node n = (node) malloc(sizeof(struct sNode));
    if (n == NULL)
        return n;

    /* Inicializo la estructura */
    n->label = label;
    n->marked = false;
    n->father = NULL;
    n->neighbors = NULL;

    assert(n != NULL);
    assert(n->neighbors == NULL);

    return n;
}

node node_destroy(node n){
    assert (n != NULL);

    /* Libero la lista de vecinos */
    g_list_free_full(n->neighbors, (GDestroyNotify) edge_destroy);
    n->neighbors = NULL;

    /* Libero la memoria alojada por el nodo */
    free(n);
    n = NULL;

    return n;
}

bool node_addNeighbor(node n1, const node n2, const unsigned int cap){
    edge e = NULL;
    assert(n1 != NULL);
    assert(n2 != NULL);
    assert(!node_neighborExists(n1,n2->label));
    
    /* Agrego la arista a la lista de vecinos del nodo */
    e = edge_create(n2, cap);
    if (e != NULL){
        n1->neighbors = g_list_append(n1->neighbors, e);
        return true;
    }else{
        return false;
    }
}

GList *node_getNeighbors(const node n){
    assert(n != NULL);

    return n->neighbors;
}

bool node_neighborExists(const node n, const unsigned int label){
    assert(n != NULL);

    /* Devolver si la arista se encontre */
    return (node_getEdge(n, label) != NULL);
}

unsigned int node_getEdgeCap(const node n, const unsigned int label){
    edge e = NULL;

    assert(n != NULL);
    assert(node_neighborExists(n, label));

    e = node_getEdge(n,label);

    return edge_getCap(e);
}

edge node_getEdge(const node n, const unsigned int label){
    GList *vecinos = n->neighbors;

    /* Recorro la lista de vecinos en busca del nodo requerido */
    while(vecinos != NULL){
        if (label == node_getLabel(edge_getNeighbor(vecinos->data))){
            /* Devuelvo la capacidad de la arista */
            return (vecinos->data);
        }
        vecinos = vecinos->next;
    }
    return NULL;
}

unsigned int node_getLabel(const node n){
    assert(n != NULL);

    return n->label;
}

unsigned int *node_getLabelAddress(const node n){
    assert(n != NULL);

    return &(n->label);
}

void node_mark(node n){
    assert(n != NULL);
    assert(!node_isMarked(n));

    n->marked = true;
}

bool node_isMarked(const node n){
    assert(n != NULL);

    return n->marked;
}

void node_setFather(node n, const node father){
    assert(n != NULL);

    n->father = father;
}

node node_getFather(const node n){
    assert(n != NULL);

    return n->father;
}

